dojo.provide("lotex.widget.Report2");

dojo.require("dojo.dom");
dojo.require("dojo.event");
dojo.require("dojo.html.*");
dojo.require("dojo.lang.common");
dojo.require("dojo.io.*");
dojo.require("dojo.string");
dojo.require("dojo.html.style");
dojo.require("dojo.widget.HtmlWidget");
dojo.require("lotex.math");
dojo.require("lotex.report.Report");
dojo.require("lotex.report.Sheet");
dojo.require("lotex.report.Functions");
dojo.require("lotex.report.Parser");
dojo.require("lotex.report.Display");

// 报表
//    Sheets
//dojo.widget.tags.addParseTreeHandler("dojo:Report2");
dojo.widget.defineWidget(
    "lotex.widget.Report2",
    dojo.widget.HtmlWidget,
{
    templatePath:null,
    templateCssPath:null,
    sheets: [],
    __output:   '__report',

    postCreate:function(){
        this.rpt = new lotex.report.Report(this.dataUri);
        dojo.event.connect(this.rpt, "load", this, "populate");
    },

    addSheet: function(sheet) {
        sheet.parent = this.rpt;
        this.sheets.push(sheet);
    },

    computeExpression: function(sheet) {
        //b(sheet.isDataSheet());
        var y = sheet.getRowLen();
        var x = sheet.getColLen();
        var sheetIdx = sheet.idx;
        for(var row=0; row<y; row++) {
            for(var col=0; col<x; col++) {
                var cell = sheet.rows[row].cells[col];
                if(cell.hasExpstr()) {
                    lotex.report.Functions.context = {"cell":cell};
                    var ex = lotex.report.Parser.parseWithCache(
                        cell.getExpstr(),
                        row, col,
                        sheetIdx, cell.getExpScope()
                        );
                    //d(ex);
                    cell.value = eval(ex);
                    //d(eval(ex));
                }
            }
        }
    },

    display: function() {
//b("display", this)
        tic();
        var len=this.sheets.length;
        var out = this.sheets[0];
        for(var i=1; i<len; i++) {
            out = out.plusV(this.sheets[i]);
        }
        this.output = dojo.byId(this.__output);
        //this.output.outerHTML = out.torsional().toStr();

        //b(out);
        var html = out.toStr();
        this.output.outerHTML = html;
        toc("output");
        //d(html);
    },

    fillInData: function(sheet){
        //if (!sheet.isDataSheet()) return;

        var data = sheet.getDataset().table;

        var hilol;
        var y = sheet.getRowLen();
        var x = sheet.getColLen();
        //var _show = data;var o = ___just_debug_break;
        // Fill Header

        var len = sheet.__header.length;
        var re = /\$\{(\w+)\}/g;

        var cfg = sheet.getConfig();
        cfg.column = {};
        for(var i=0; i<len; i++) {
            var row = sheet.__header[i];
            for(var col=0; col<x; col++) {
                var cell = sheet.rows[row].cells[col];
                //if(cell.beMerge) continue;
                cell.text = cell.text.replace(
                            re,
                            function(match,key) {
                                if(dj_undef(key,data.field)) return match;
                                cfg.column[col] = {};
                                cfg.column[col].fid = key;
                                var str = data.field[key].caption;
                                cell.value = str;
                                return str;
                            })
            }
        }

        // New fill method
        var regexp = /\$\{((\w+)\.(\w+))\}/i;
        for(var r=0; r<y; r++) {
            // maybe have bug on skip same line need getdata
            if (sheet.rows[r].getConfigItem(
                    "expanded")) continue;
            for(var c=0; c<x; c++) {
                var cell = sheet.rows[r].cells[c];
                //cell.addClassName("__rptflag");
                var ss = cell.text;
                var match = ss.match(regexp);
                if (match!=null) {
                    // Now Only Expand down
                    var ds = match[2];
//if(ds=="ds2")b();
                    var col = match[3];
                    var da = this.rpt.getDataset(ds).getData(col);
                    var len = da.length;
                    var useableRowNum = 1;


                    while(sheet.rows[r+useableRowNum].getConfigItem(
                            "expanded")) {
                        useableRowNum++;
                    }

                    // find expand border
                    var haveSetBorder = false;
                    for(var ff = r + useableRowNum; ff<y;ff++) {
                        if (regexp.test(sheet.rows[ff].cells[c].text)) {
                            useableRowNum += ff - r - 1;
                            break;
                        }
                        if (sheet.rows[ff].getConfigItem(
                                "expand_down_border")) {
                            haveSetBorder = true;
                            useableRowNum += ff - r;
                            break;
                        }
                    }

                    exstart = r;
                    if(useableRowNum<len) {
                        var dis = len - useableRowNum ;
                        var beCloneRow = sheet.rows[r+useableRowNum-1];
                        if(haveSetBorder)
                            beCloneRow.delConfigItem("expand_down_border");
                        var expandedRow =
                            sheet.rows[r+useableRowNum-1].clone();

                        var ll = beCloneRow.cells.length;
                        for(var ii=0; ii<ll; ii++) {
                            if (beCloneRow.cells[ii].getConfigItem(
                                    "onexpand")=="flex") {
                                beCloneRow.cells[ii].rowSpan += dis;
                                expandedRow.cells[ii].beMerge = true;
                            }
                        }

                        //expandedRow.setConfigItem("expanded");
                        for(var ii=0; ii<dis; ii++) {
                            sheet.insertRow(
                                r + useableRowNum, expandedRow.clone());
                        }
                        if(haveSetBorder)
                            sheet.rows[r+len-1].setConfigItem(
                                "expand_down_border");
                        //r += dis;
                        y += dis;
                    }

                    // fill in data
                    for(var ff=0; ff<len; ff++) {
                        var fill = da[ff];
                        if (fill != null && fill != "")
                            var fillrow = sheet.rows[exstart+ff];
                            fillrow.setConfigItem("expanded");
                            var fillcell = fillrow.cells[c];
                            fillcell.text = ss;
                            fillcell.value = fill;
                            fillcell.isData = true;
                    }
                }
            }
        }
    },

    getSheet: function(n) {
        if(!n) return this.sheets[0];
        return this.sheets[n];
    },

    // add arg: sheet, scope
    getCell: function(col,row,sheet,scope) {
        var st = this.getSheet(sheet);
        return st.getCell(col,row,scope);
    },

    readSheets: function() {
        // 从DOM把工作表分离出来。
        function getSheetsFromDOM(dom) {
            return dojo.html.getElementsByClass
                ('--sheet',dom,'table');
        };

        tic();
        var sheets = getSheetsFromDOM(this.domNode);

        var len = sheets.length;
        for(var i=0; i<len; i++) {
            var st = new lotex.report.Sheet(sheets[i], i);
            this.addSheet(st);
        }
        toc("读取模版中的工作表");
        //b(this);
    },

    populate: function() {
        tic();
        // process report attribute
        // TODO move to..

        // 解释宏
        function processMacros(macroWord) {
            switch (macroWord){
               case 'TODAY':
                   return lotex.report.Functions.today();
               case 'VERSION':
                   return lotex.version.toString();
               default:
                   return false;
            }
        };

        // 抽取 ${}
        var kwRegexp = /\$\{(\w+)\}/g;
        var define = this.rpt.define;
        window.document.title = "" + define['title'];

        var ret = this.rpt['template'].replace(
                    kwRegexp,
                    function(match,key) {
                        return processMacros(key) || (
                            dj_undef(key, define) ? match : define[key]);
                    });

        this.domNode.innerHTML = ret;
        toc('处理模版中的宏和报表属性，并将处理后的模版放入DOM');

        this.process();


        // only use in develop
        //this.readSheets();
        //this.fillInData(this.sheets[0]);

    },

    prepareData: function() {
    },

    process: function() {
        this.prepareData();
        this.readSheets();
        //b2(this);
        //debugger;
        var len=this.sheets.length;
        for(var i=0; i<len; i++) {
            var sheet = this.sheets[i];
            tic();
            this.fillInData(sheet);
            toc('fill data of sheet['+i+']');

            tic();
            //  Compute reports function
            this.computeExpression(sheet);
            toc('compute report expression of sheet['+i+']');

            tic();
            //this.processGroup(sheet);
            toc('process group of sheet['+i+']');

            tic();
            //  Compute display rule
            lotex.report.Display.process(sheet);
            toc('process display rule of sheet['+i+']');

        }

        this.display();
        b(this.sheets[0]);
    },

    processGroup: function(sheet) {
        if (!sheet.isDataSheet()) return;

        var g = sheet.__group;
        if(g.length <1 ) return;

        var cfg = g[0].getConfig();
        var gname = cfg.group;
        var group = sheet.getDataset().group[gname];

        var len = group.length;
        var x = g[0].cell.length;
        var sheetIdx = sheet.idx;

        for(var i=0;i<len;i++) {
            var ga = group[i];
            var inpos = ga[ga.length-1] + 2 + i;
            var row = g[0].clone();
            for(var col=0; col<x; col++) {
                var cell = row.cells[col];
                if(cell.hasExpstr()) {
                    lotex.report.Functions.context = {"cell":cell};
                    var ex = lotex.report.Parser.parseWithCache(
                        cell.getExpstr(),
                        inpos, col,
                        sheetIdx, cell.getExpScope()
                        );
                    //d(ex);
                    cell.value = eval(ex);
                    cell.text = cell.value;
                    //d(eval(ex));
                }
            }
            sheet.insertInExpand(inpos,row);
        }
    }
});